package com.moonbird.springboot.Utils.RecognitionImage;

import com.google.gson.Gson;
import okhttp3.HttpUrl;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

public class FormRecognitionUtil {
    // 地址与鉴权信息
    public static final String hostUrl = "https://ws-api.xf-yun.com/v1/private/ma008db16";
    public static final String appid = "f9173867";
    public static final String apiSecret = "MTNjM2UxN2NkMmUyZTQzNDIxN2UxOGRm";
    public static final String apiKey = "a6e589a40b3eb2bad249c299fb440c5d";
    // json
    public static final Gson gson = new Gson();
    public static boolean wsCloseFlag = false;

    public static String recognizeForm(String imageFilePath, String resultType, String outputDirectory) throws Exception {
        String wsUrl = getAuthUrl(hostUrl, apiKey, apiSecret).replace("https://", "wss://");
        return websocketWork(wsUrl, imageFilePath, resultType, outputDirectory);
    }

    // Websocket方法
    public static String websocketWork(String wsUrl, String imageFilePath, String resultType, String outputDirectory) throws Exception {
        final String[] outputFilePath = {""};
        try {
            URI uri = new URI(wsUrl);
            WebSocketClient webSocketClient = new WebSocketClient(uri) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    System.out.println("ws建立连接成功...");
                }

                @Override
                public void onMessage(String text) {
                    JsonParse myJsonParse = gson.fromJson(text, JsonParse.class);
                    if (myJsonParse.header.code != 0) {
                        System.out.println("发生错误，错误码为：" + myJsonParse.header.code);
                        System.out.println("本次请求的sid为：" + myJsonParse.header.sid);
                    }
                    if (myJsonParse.header.status == 1) {
                        try {
                            // 根据resultType设置输出文件的扩展名
                            String fileExtension = getFileExtension(resultType);
                            String outputFileName = UUID.randomUUID().toString() + fileExtension;
                            outputFilePath[0] = outputDirectory + File.separator + outputFileName;

                            OutputStream outputStream = new FileOutputStream(outputFilePath[0]);
                            byte[] textBase64Decode = Base64.getDecoder().decode(myJsonParse.payload.result.text);
                            outputStream.write(textBase64Decode);
                            outputStream.close();
                            System.out.println("表格识别成功，文件保存路径为==>" + outputFilePath[0]);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        System.out.println("本次请求的sid==>" + myJsonParse.header.sid);
                    } else if (myJsonParse.header.status == 2) {
                        // 可以关闭连接，释放资源
                        wsCloseFlag = true;
                    }
                }

                @Override
                public void onClose(int i, String s, boolean b) {
                    System.out.println("ws链接已关闭，本次请求完成...");
                }

                @Override
                public void onError(Exception e) {
                    System.out.println(e.getMessage());
                }
            };
            // 建立连接
            webSocketClient.connect();
            while (!webSocketClient.getReadyState().equals(WebSocket.READYSTATE.OPEN)) {
                Thread.sleep(100);
            }
            MyThread webSocketThread = new MyThread(webSocketClient, imageFilePath, resultType);
            webSocketThread.start();
            // 等待服务端返回完毕后关闭
            while (!wsCloseFlag) {
                Thread.sleep(200);
            }
            webSocketClient.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return outputFilePath[0];
    }

    // 线程来发送图片与参数
    static class MyThread extends Thread {
        WebSocketClient webSocketClient;
        String imageFilePath;
        String resultType;

        public MyThread(WebSocketClient webSocketClient, String imageFilePath, String resultType) {
            this.webSocketClient = webSocketClient;
            this.imageFilePath = imageFilePath;
            this.resultType = resultType;
        }

        public void run() {
            String requestJson;//请求json串
            try {
                requestJson = "{\n" +
                        "  \"header\": {\n" +
                        "    \"app_id\": \"" + appid + "\",\n" +
                        "    \"status\":2\n" +
                        "  },\n" +
                        "  \"parameter\": {\n" +
                        "    \"s15282f39\": {\n" +
                        "      \"category\": \"ch_en_public_cloud\",\n" +
                        "      \"result\": {\n" +
                        "        \"encoding\": \"utf8\",\n" +
                        "        \"compress\": \"raw\",\n" +
                        "        \"format\": \"plain\"\n" +
                        "      }\n" +
                        "    },\n" +
                        "    \"s5eac762f\": {\n" +
                        "      \"result_type\": \"" + resultType + "\",\n" +
                        "      \"result\": {\n" +
                        "        \"encoding\": \"utf8\",\n" +
                        "        \"compress\": \"raw\",\n" +
                        "        \"format\": \"plain\"\n" +
                        "      }\n" +
                        "    }\n" +
                        "  },\n" +
                        "  \"payload\": {\n" +
                        "    \"test\": {\n" +
                        "      \"encoding\": \"" + imageFilePath.substring(imageFilePath.length() - 3) + "\",\n" +
                        "      \"image\": \"" + Base64.getEncoder().encodeToString(read(imageFilePath)) + "\",\n" +
                        "      \"status\": 3\n" +
                        "    }\n" +
                        "  }\n" +
                        "}";
                webSocketClient.send(requestJson);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 读取文件数据
    public static byte[] read(String filePath) throws IOException {
        InputStream in = new FileInputStream(filePath);
        byte[] data = inputStream2ByteArray(in);
        in.close();
        return data;
    }

    private static byte[] inputStream2ByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    // 鉴权方法
    public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        // 时间
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // 拼接
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        // Base64加密
        String sha = Base64.getEncoder().encodeToString(hexDigits);
        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().//
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).//
                addQueryParameter("date", date).//
                addQueryParameter("host", url.getHost()).//
                build();

        return httpUrl.toString();
    }

    // 获取文件扩展名
    private static String getFileExtension(String resultType) {
        switch (resultType) {
            case "0":
                return ".xlsx";
            case "1":
                return ".docx";
            case "2":
                return ".pptx";
            default:
                throw new IllegalArgumentException("Unsupported result type: " + resultType);
        }
    }
}

class JsonParse {
    public Header header;
    public Payload payload;
}

class Header {
    public int code;
    public int status;
    public String sid;
}

class Payload {
    public Result result;
}

class Result {
    public String text;
}
